package com.kama.minispring.beans.factory.annotation;

import com.kama.minispring.beans.BeansException;
import com.kama.minispring.beans.factory.BeanFactory;
import com.kama.minispring.beans.factory.BeanFactoryAware;
import com.kama.minispring.beans.factory.config.InstantiationAwareBeanPostProcessor;
import com.kama.minispring.beans.factory.config.PropertyValues;

import java.lang.reflect.Field;

/**
 * 处理@Autowired注解的BeanPostProcessor实现
 * 负责自动注入依赖的功能
 *
 * @author kama
 * @version 1.0.0
 */
public class AutowiredAnnotationBeanPostProcessor implements InstantiationAwareBeanPostProcessor, BeanFactoryAware {

    private BeanFactory beanFactory;

    /**
     * 设置BeanFactory
     *
     * @param beanFactory Bean工厂
     */
    @Override
    public void setBeanFactory(BeanFactory beanFactory) {
        this.beanFactory = beanFactory;
    }

    /**
     * 在实例化Bean之前进行处理
     *
     * @param beanClass Bean类
     * @param beanName  Bean名称
     * @return 处理后的Bean实例，如果返回null，则继续执行默认实例化逻辑
     * @throws BeansException 如果处理失败
     */
    @Override
    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
        return null;
    }

    /**
     * 在实例化Bean之后进行处理
     *
     * @param bean      Bean实例
     * @param beanName  Bean名称
     * @return 如果返回false，则跳过当前Bean的依赖注入
     * @throws BeansException 如果处理失败
     */
    @Override
    public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
        return true;
    }

    /**
     * 在设置Bean属性值之前进行处理
     *
     * @param pvs    PropertyValues对象，包含待设置的属性值
     * @param bean   Bean实例
     * @param beanName  Bean名称
     * @return 处理后的PropertyValues对象
     * @throws BeansException 如果处理失败
     */
    @Override
    public PropertyValues postProcessPropertyValues(PropertyValues pvs, Object bean, String beanName) throws BeansException {
        // 获取当前bean的类信息
        Class<?> clazz = bean.getClass();
        // 获取类中所有声明的字段
        Field[] fields = clazz.getDeclaredFields();

        // 遍历每个字段以处理@Autowired注解
        for (Field field : fields) {
            // 获取字段上的@Autowired注解
            Autowired autowired = field.getAnnotation(Autowired.class);
            // 如果字段上有@Autowired注解
            if (autowired != null) {
                // 获取需要自动注入的bean名称，即字段名
                String autowiredBeanName = field.getName();
                // 从bean工厂中获取对应名称的bean实例
                Object autowiredBean = beanFactory.getBean(autowiredBeanName);

                // 如果未找到对应名称的bean实例且该字段被标记为必需自动注入
                if (autowiredBean == null && autowired.required()) {
                    // 抛出异常，指示无法自动注入必需的字段
                    throw new BeansException("Could not autowire required field: " + field.getName());
                }

                // 如果找到了对应名称的bean实例
                if (autowiredBean != null) {
                    // 设置字段可访问，以绕过访问控制检查
                    field.setAccessible(true);
                    try {
                        // 将找到的bean实例注入到当前字段中
                        field.set(bean, autowiredBean);
                    } catch (IllegalAccessException e) {
                        // 如果注入失败，抛出异常，指示无法自动注入字段
                        throw new BeansException("Could not autowire field: " + field.getName(), e);
                    }
                }
            }
        }
        return pvs;
    }

    /**
     * 在初始化Bean之前进行处理
     *
     * @param bean   Bean实例
     * @param beanName  Bean名称
     * @return 处理后的Bean实例
     * @throws BeansException 如果处理失败
     */
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }

    /**
     * 在初始化Bean之后进行处理
     *
     * @param bean   Bean实例
     * @param beanName  Bean名称
     * @return 处理后的Bean实例
     * @throws BeansException 如果处理失败
     */
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }
}
